#include "GlWindow.h"
#include "Siosis_Logo_v1.h"
#include "Menu_Shard_Class.h"
#include <string>

bool	kd   = FALSE;	// For input in menu - stops rapid movement.
bool	ku   = FALSE;	// For input in menu - stops rapid movement.
int		woP  = 1;		// Which menu option is selected.
bool	done = FALSE;	// Bool Variable To Exit Loop (in main()).
shard	shards[7];		// 7 Shards created to draw the Main Menu.
MenuShard mshards[3];	// 3 Menu_Shards.
int		WhichMenu = 1;	// We start off in the Main Menu.

float tip = 0.0;		// Value of the court's rotation on the X-axis.
float rot = 0.0;		// Value of the court's rotation on the X-axis.

unsigned int padel;		// Storage for our padel model - compiled in a display list.
unsigned int puck;
unsigned int skirt;

float	score1;			// Players scores.
float	score2;
bool	lpR1;			// Last key was RIGHT?
bool	lpR2;			// Last key was RIGHT?	 -  for directing the puck.
bool    ScoreAllowed;	// Multiple points cannot be scored from one shot.
bool	AtTop;			// Tracks which end of the court the puck is.

struct Padel
{
	float X;		// Position.
	float Y;
	float sp[4];	// Speeds.
	float acc;		// Acceleration.
	float dac;		// Decceleration.
};

struct Puck	 
{
	float X;		// Position.
	float Y;
	bool  sp[4];	// Speeds. NB: A puck moves at the top_speed for a padel, i.e. 'TOP'.
	float speed;
};


Puck puk;			// One puck.
Padel pad[2];		// Two padels.

#define ACC				0.006f					// Acceleration.
#define DAC				0.0f					// Deceleration.
#define TOP				0.0245f					// Top Speed.
#define PADEL_LENGTH	0.12f
#define PADEL_HEIGHT	0.056f
#define PUCK_LENGTH		0.04f
#define PUCK_HEIGHT		0.04f
#define PUCK_SKIRT		0.08f					// Amount skirt flares at bottom.
#define MIN_PUCK_SPEED	0.02f
#define MAX_PUCK_SPEED	0.07f					
#define GLOW_RATE		0.05f

void
Ai(std::string ai_bot)
{
	if (ai_bot == "Taknitzu")
	{
		if (pad[1].X < puk.X) { keys['D'] = TRUE; keys['A'] = FALSE; }
		if (pad[1].X > puk.X) { keys['A'] = TRUE; keys['D'] = FALSE; }
	
		if (puk.Y > 0.0f) 
		{
			keys['W'] = TRUE; keys['S'] = FALSE; 
			if (pad[1].Y > puk.Y) { keys['S'] = TRUE; keys['W'] = FALSE; }
		}
	}

	if (ai_bot == "Matazuri")
	{
		if (pad[1].X < puk.X) { keys['D'] = TRUE; keys['A'] = FALSE; }
		if (pad[1].X > puk.X) { keys['A'] = TRUE; keys['D'] = FALSE; }
	
		if (puk.sp[1] == TRUE) 
		{
			keys['W'] = TRUE; keys['S'] = FALSE; 
			if (pad[1].Y > puk.Y) { keys['S'] = TRUE; keys['W'] = FALSE; }
		}
	}

}

void 
SetUpGame()
{
	for (int t = 0; t < 2; t++)
	{
		pad[t].acc = ACC;
		pad[t].dac = DAC;
		
		for (int tt = 0; tt < 4; tt++) 
		{
			pad[t].sp[tt] = 0.0f;	// Padels Stationary.
			puk.sp[tt] = FALSE;		// Puck stationary.
		}

		pad[t].X = 0.0;
	}
	
	keys['W'] = FALSE;
	keys['S'] = FALSE;
	keys['A'] = FALSE;
	keys['D'] = FALSE;

	pad[0].Y =  0.75;
	pad[1].Y =  0.75;
	
	// Puck always starts in the centre of the court.
	puk.X = 0.0f;
	puk.Y = 0.0001f;
	puk.speed = MIN_PUCK_SPEED;
	score1 = 0;				// Set player scores to zero.
	score2 = 0;
	ScoreAllowed = TRUE;    // First shot is capable if winning a point.
	AtTop = TRUE;			// Puck starts just inside top half of court.

	// Set Up the puck's initial direction.
	srand(GetTickCount());		// Seed for random number.
	unsigned int r = rand()%4;	// Will puck go up (<=2) or down (>=3)?
	if (r < 3)	puk.sp[1] = TRUE; else puk.sp[3] = TRUE;
	if (r%2)	puk.sp[0] = TRUE; else puk.sp[2] = TRUE;
	BASS_Start();		// Make sounds available.
	BASS_StreamPlay(game_music,FALSE,BASS_SAMPLE_LOOP);
}

void
BuildLists()
{
	padel = glGenLists(3);	// Room for 3 lists.
	
	glNewList(padel, GL_COMPILE);			// Start of list.
		
		glBegin(GL_QUADS);
			glNormal3f(0.0f, -0.5f, 0.5f);
			// Top right.
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-PADEL_LENGTH, 0.0f, 0.0f);
			// Bottom right.
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-PADEL_LENGTH, -PADEL_HEIGHT, -0.09f);
			// Bottom left.
			glTexCoord2f(0.0f, 1.0f); glVertex3f(PADEL_LENGTH, -PADEL_HEIGHT, -0.09f);
			// Top left.
			glTexCoord2f(0.0f, 0.0f); glVertex3f(PADEL_LENGTH, 0.0f, 0.0f);

			glNormal3f(0.0f, 0.5f, 0.5f);
			// Top right.
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-PADEL_LENGTH, PADEL_HEIGHT, -0.09f);
			// Bottom right.
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-PADEL_LENGTH, 0.0f, -0.0f);
			// Bottom left.
			glTexCoord2f(0.0f, 1.0f); glVertex3f(PADEL_LENGTH, 0.0f, -0.0f);
			// Top left.
			glTexCoord2f(0.0f, 0.0f); glVertex3f(PADEL_LENGTH, PADEL_HEIGHT, -0.09f);
		glEnd();

	glEndList();							// End of list.

	//puck = 0;
	puck = padel + 1;

	glNewList(puck, GL_COMPILE);			// Start of list.
		
		glBegin(GL_QUADS);
			glNormal3f(0.0f, 0.0f, 1.0f);
	
			// Top of puck: -
			// Top right.
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-PUCK_LENGTH, -PUCK_HEIGHT, 0.0f);
		
			// Bottom right.
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-PUCK_LENGTH, PUCK_HEIGHT, 0.0f);

			// Bottom left.
			glTexCoord2f(0.0f, 1.0f); glVertex3f(PUCK_LENGTH, PUCK_HEIGHT, 0.0f);

			// Top left.
			glTexCoord2f(0.0f, 0.0f); glVertex3f(PUCK_LENGTH, -PUCK_HEIGHT, 0.0f);
		
			
					
			glEnd();

	glEndList();							// End of list.
	
	skirt = puck + 1;
	
	glNewList(skirt, GL_COMPILE);
			
			glBegin(GL_QUADS);
					
			// Top right.
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-PUCK_LENGTH, PUCK_HEIGHT, 0.0f);
		
			// Bottom right.
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-PUCK_LENGTH - PUCK_SKIRT, PUCK_HEIGHT + PUCK_SKIRT, -0.09f);

			// Bottom left.
			glTexCoord2f(0.0f, 1.0f); glVertex3f(PUCK_LENGTH + PUCK_SKIRT, PUCK_HEIGHT + PUCK_SKIRT, -0.09f);

			// Top left.
			glTexCoord2f(0.0f, 0.0f); glVertex3f(PUCK_LENGTH, PUCK_HEIGHT, 0.0f);
			
			glEnd();

	glEndList();							// End of list.


}

void
DrawScores()
{						
	// Player Scores...

	
	glLoadIdentity();
	glDisable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, g_Texture[9]);
	glTranslatef(0.0f, -4.0f, -10.0f);
	
	glColor3f(1.0f, 1.0f, 1.0f);		
	glPrint("%3.0f                               %3.0f",score1,score2);


}

inline void
DrawCourt()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glColor3f(1.0f,1.0f,1.0f);
	glEnable(GL_TEXTURE_2D);
	
	glBindTexture(GL_TEXTURE_2D, g_Texture[9]);
	glBegin(GL_QUADS);
		glNormal3f(0.0f, 0.0f, 1.0f);
	
		// Top right.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-11.0f, -11.0f, -14.0f);
		
		// Bottom right.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-11.0f, 11.0f, -14.0f);

		// Bottom left.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(11.0f, 11.0f, -14.0f);

		// Top left.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(11.0f, -11.0f, -14.0f);

	glEnd();


	glBindTexture(GL_TEXTURE_2D, g_Texture[11]);

	// ################################################################
		// Orientation.
		glRotatef(tip, 1.0f, 0.0f, 0.0f);
		glRotatef(rot, 0.0f, 0.0f, 1.0f);
		glTranslatef(0.0f, -(tip/10), 0.0f); 
		
	// ################################################################
	
	glColor4f(1.0f,1.0f,1.0f,0.5f);
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 
	glEnable(GL_BLEND);

	glBegin(GL_QUADS);
		glNormal3f(0.0f, 0.0f, 1.0f);
	
		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.6f, -4.2f);
		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.6f, -4.2f);

		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.6f, -4.2f);

		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.6f, -4.2f);

	glEnd();

	// Padels are drawn below here: -
	glBindTexture(GL_TEXTURE_2D ,g_Texture[13]);
	for (int t = 0; t < 2; t++)
	{
		glLoadIdentity();
		// ################################################################
		// Orientation.
		glRotatef(tip, 1.0f, 0.0f, 0.0f);
		glRotatef(rot, 0.0f, 0.0f, 1.0f);
		glTranslatef(0.0f, -(tip/10), 0.0f);	
		glTranslatef((float)pad[t].X, (float)pad[t].Y, -4.09f);		
		// ################################################################
		if (t==0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f); else glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
		//glEnable(GL_BLEND);
		//glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
		glCallList(padel);
	}

	// Draw Net and Sides.
	glLoadIdentity();
		// ################################################################
		// Orientation.
		glRotatef(tip, 1.0f, 0.0f, 0.0f);
		glRotatef(rot, 0.0f, 0.0f, 1.0f);
		glTranslatef(0.0f, -(tip/10), 0.0f);		
		// ################################################################
	glBindTexture(GL_TEXTURE_2D, g_Texture[16]);	
	glColor4f(1.0f,1.0f,1.0f,0.01f);
	glBegin(GL_QUADS);
		// The Net.
		glNormal3f(0.0f, -1.0f, 0.0f);

		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 0.0f, -4.2f);
		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 0.0f, -4.0f);

		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 0.0f, -4.0f);

		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, 0.0f, -4.2f);
	
		// Top Part of the Net.
		glNormal3f(0.0f, 0.0f, 1.0f);

		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -0.02f, -4.0f);
		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 0.02f, -4.0f);

		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 0.02f, -4.0f);

		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -0.02f, -4.0f);

	glEnd();

	glBindTexture(GL_TEXTURE_2D ,g_Texture[16]);

	glBegin(GL_QUADS);
		// Bottom Side.
		glNormal3f(0.0f, 1.0f, 0.0f);
		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.6f, -4.2f);		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.6f, -4.0f);
		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.6f, -4.0f);
		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.6f, -4.2f);

		// Top Side.
		glNormal3f(0.0f, -1.0f, 0.0f);		
		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.6f, -4.2f);		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.6f, -4.0f);
		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.6f, -4.0f);
		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, 1.6f, -4.2f);
	glEnd();

	glBindTexture(GL_TEXTURE_2D ,g_Texture[16]);
	glBegin(GL_QUADS);
		// Left Side.
		glNormal3f(1.0f, 0.0f, 0.0f);		
		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.6f, -4.2f);		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.6f, -4.0f);
		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.6f, -4.0f);
		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.6f, -4.2f);
	
		// Right Side.
		glNormal3f(-1.0f, 0.0f, 0.0f);		
		// Top right.
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.6f, -4.2f);		
		// Bottom right.
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.6f, -4.0f);
		// Bottom left.
		glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.6f, -4.0f);
		// Top left.
		glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.6f, -4.2f);
	glEnd();
	
	glDisable(GL_BLEND);

	
	
	// Draw the puck: -
	glBindTexture(GL_TEXTURE_2D, g_Texture[15]);
	glLoadIdentity();
	// ################################################################
	// Orientation.
	glRotatef(tip, 1.0f, 0.0f, 0.0f);
	glRotatef(rot, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, -(tip/10), 0.0f);	
	glTranslatef((float)puk.X, (float)puk.Y, -4.09f);		
	// ################################################################
	glColor3f(1.0f, 1.0f, 1.0f);
	glCallList(puck);
	glBindTexture(GL_TEXTURE_2D, g_Texture[16]);
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);

// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Glowing effect of puck's skirt.

	static float GLOW = 0.01f;
	static bool G_UP = TRUE;
	if (G_UP) GLOW += GLOW_RATE; else GLOW -= GLOW_RATE;
	if (GLOW>1.0f) G_UP = FALSE;
	if (GLOW<0.01f) G_UP = TRUE;

	glColor4f(1.0f*GLOW, 1.0f*GLOW, 1.0f*GLOW, 0.5f*GLOW);
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

	glCallList(skirt);	// Top.
	glRotatef(90, 0.0f,0.0f, 1.0f);
	glCallList(skirt);
	glRotatef(180, 0.0f,0.0f, 1.0f);
	glCallList(skirt);
	glRotatef(270, 0.0f,0.0f, 1.0f);
	glCallList(skirt);
	glDisable(GL_BLEND);

	DrawScores();

}

void DrawMenu(int woP)								
{
	// Draw the rotating Siosis sign :D
	glDisable(GL_BLEND);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear screen.
	glLoadIdentity();			// Reset The Current Modelview Matrix
	glColor3f(1.0f,1.0f,1.0f);	// Sets drawing colour to white.	
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,  g_Texture[8]);

	static float RV;
	RV += 0.1f;
	glRotatef(RV,0.0f,0.0f,1.0f);
	glBegin(GL_QUADS);
		glTexCoord2f(1.0f,0.0f);glVertex3f(9.0f,-9.0f,-12.0f);
		glTexCoord2f(0.0f,0.0f);glVertex3f(-9.0f,-9.0f,-12.0f);
		glTexCoord2f(0.0f,1.0f);glVertex3f(-9.0f,9.0f,-12.0f);
		glTexCoord2f(1.0f,1.0f);glVertex3f(9.0f,9.0f,-12.0f);
	glEnd();

	for(int ti = 3; ti < 4; ti++) 
	{
		shards[3].Rot();
		shards[ti].Draw();
		mshards[ti].Draw();
	}
	
	// This draws the 'Torsion' Logo :D
	glLoadIdentity();
	glTranslatef(-0.3f, 0.9f, 0.0f);
	glEnable(GL_BLEND);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	glBlendFunc(GL_DST_COLOR, GL_ZERO);
	glBindTexture(GL_TEXTURE_2D, g_Texture[12]);
	glBegin(GL_QUADS);
		glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,-4.0f);
		glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,-4.0f);
		glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-4.0f);
		glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-4.0f);
	glEnd();

	glBlendFunc(GL_ONE, GL_ONE);
	glBindTexture(GL_TEXTURE_2D, g_Texture[2]);
	glBegin(GL_QUADS);
		glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,-4.0f);
		glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,-4.0f);
		glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-4.0f);
		glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-4.0f);
	glEnd(); 

	// Decide which texture to use.
	if(woP==1) glBindTexture(GL_TEXTURE_2D,  g_Texture[4]);
	if(woP==2) glBindTexture(GL_TEXTURE_2D,  g_Texture[5]);
	if(woP==3) glBindTexture(GL_TEXTURE_2D,  g_Texture[6]);
	if(woP==4) glBindTexture(GL_TEXTURE_2D,  g_Texture[7]);
	
	// Draw the centre-menu.
	glLoadIdentity();	
	
	//Very nice effect.
	/*
	glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); 
	glEnable(GL_BLEND);
	glColor4f(1.0f,1.0f,1.0f,1.0f); */
	
	glColor4f(1.0f,1.0f,1.0f,0.5f);
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

	glEnable(GL_BLEND);
	

	glBegin(GL_QUADS);
		glTexCoord2f(1.0f,0.0f);glVertex3f(0.4f,-0.4f,-2.4f);
		glTexCoord2f(0.0f,0.0f);glVertex3f(-0.4f,-0.4f,-2.4f);
		glTexCoord2f(0.0f,1.0f);glVertex3f(-0.4f,0.4f,-2.4f);
		glTexCoord2f(1.0f,1.0f);glVertex3f(0.4f,0.4f,-2.4f);
	glEnd();

}

void InitMenu()
{
		// Hey! Let's make the menu out of shards!
		
		// Top left shard.
		mshards[0].SetHeight(1.0f);
		mshards[0].SetWidth(1.0f);
		mshards[0].SetSpeed(0.0f);	
		mshards[0].SetRotation(0.0f);	// No Rotation.
		mshards[0].SetX(-2.6f);
		mshards[0].SetY(1.9f);
		mshards[0].SetZ(-6.0f);
		mshards[0].SetTexture(0); 
		//CreateTexture(g_Texture, "Data/Images/Fin1.bmp", 0); // Load "Fin1.bmp" into openGL as a texture.

		// Bottom right shard.
		mshards[1].SetHeight(1.0f);
		mshards[1].SetWidth(1.0f);
		mshards[1].SetSpeed(0.0f);	
		mshards[1].SetRotation(0.0f);	// No Rotation.
		mshards[1].SetX(2.6f);
		mshards[1].SetY(-1.9f);
		mshards[1].SetZ(-6.0f);
		mshards[1].SetTexture(1); 
		//CreateTexture(g_Texture, "Data/Images/Fin2.bmp", 1); // Load "Fin2.bmp" into openGL as a texture.
		
		// Torsion sign.
		mshards[2].SetHeight(1.0f);
		mshards[2].SetWidth(1.0f);
		mshards[2].SetSpeed(0.0f);	
		mshards[2].SetRotation(0.0f);	// No Rotation.
		mshards[2].SetX(-0.4f);
		mshards[2].SetY(0.9f);
		mshards[2].SetZ(-3.0f);
		mshards[2].SetTexture(2); 
		CreateTexture(g_Texture, "Data/Images/Torsion1.bmp", 2); // Load "Fin2.bmp" into openGL as a texture.

		// Spinning Siosis Sign (bottom left).
		shards[3].SetHeight(0.4f);
		shards[3].SetWidth(0.4f);
		shards[3].SetSpeed(0.8f);	
		shards[3].SetRotation(1.0f);
		shards[3].SetX(-1.9f);
		shards[3].SetY(-1.15f);
		shards[3].SetZ(-4.0f);
		shards[3].SetTexture(3); 
		CreateTexture(g_Texture, "Data/Images/Siosisv1.bmp", 3); // Load "Fin2.bmp" into openGL as a texture.
		
		// Create the textures for the centre-menu. 
		CreateTexture(g_Texture, "Data/Images/Menu_1.bmp", 4); 
		CreateTexture(g_Texture, "Data/Images/Menu_2.bmp", 5);
		CreateTexture(g_Texture, "Data/Images/Menu_3.bmp", 6);
		CreateTexture(g_Texture, "Data/Images/Menu_4.bmp", 7);
		CreateTexture(g_Texture, "Data/Images/Back1.bmp", 8);

		// Start the music.
		menu_music=BASS_StreamCreateFile(FALSE,"Data/Sounds/menu_song.mp3",0,0,BASS_MUSIC_3D);	// Load Menu music.							
		BASS_SetVolume(100);
		BASS_Start();																					
		BASS_StreamPlay(menu_music,FALSE,BASS_SAMPLE_LOOP);
		click[0] = BASS_StreamCreateFile(FALSE,"Data/Sounds/sm.mp3",0,0,BASS_MUSIC_3D);			// Load Click sound.
		click[1] = BASS_StreamCreateFile(FALSE,"Data/Sounds/sm.mp3",0,0,BASS_MUSIC_3D);	
		click[2] = BASS_StreamCreateFile(FALSE,"Data/Sounds/sm.mp3",0,0,BASS_MUSIC_3D);	
		click[3] = BASS_StreamCreateFile(FALSE,"Data/Sounds/sm.mp3",0,0,BASS_MUSIC_3D);	
		puck_impact[0]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact.mp3",0,0,BASS_MUSIC_3D);
		puck_impact[1]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact.mp3",0,0,BASS_MUSIC_3D);
		puck_impact[2]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact.mp3",0,0,BASS_MUSIC_3D);
		puck_impact[3]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact.mp3",0,0,BASS_MUSIC_3D);
		game_music=BASS_StreamCreateFile(FALSE,"Data/Sounds/game_music.mp3",0,0,BASS_MUSIC_3D);	// Load Menu music.	

		puck_impact2[0]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact2.mp3",0,0,BASS_MUSIC_3D);
		puck_impact2[1]=BASS_StreamCreateFile(FALSE,"Data/Sounds/puck_impact2.mp3",0,0,BASS_MUSIC_3D);

		// Load textures for the court:-
		CreateTexture(g_Texture, "Data/Images/MetalFog2.bmp", 9);
		//CreateTexture(g_Texture, "Data/Images/SidePanel.bmp", 10);
		CreateTexture(g_Texture, "Data/Images/Court.bmp", 11);
		CreateTexture(g_Texture, "Data/Images/Torsion1_mask.bmp", 12);
		CreateTexture(g_Texture, "Data/Images/pad.bmp", 13);
		//CreateTexture(g_Texture, "Data/Images/MetalFog.bmp", 14);
		CreateTexture(g_Texture, "Data/Images/Puck.bmp", 15);
		CreateTexture(g_Texture, "Data/Images/Skirt.bmp", 16);
		// Build Display Lists.
		BuildLists();
}

void
Game_CheckKeys()
{
	if (keys[VK_ESCAPE])	// Was ESC Pressed?
	{
		WhichMenu = 1;		// Go back to main menu.
		woP = 1;			// Single Player Game Selected again.
		//BASS_SetVolume(10);
		BASS_Stop();
		BASS_Start();																					
		BASS_StreamPlay(menu_music,FALSE,BASS_SAMPLE_LOOP);
	}
	
	if(keys[VK_CONTROL])	// Whilst holding down CTRL...
	{
		if(keys[VK_DOWN])	tip-=0.4f;
		if(keys[VK_UP])		tip+=0.4f;
		if(keys[VK_RIGHT])	rot-=0.4f;
		if(keys[VK_LEFT])	rot+=0.4f;
		if(tip < -70.0f)	tip = -70.0f;
		if(tip > 70.0f)		tip = 70.0f;
		if(rot < -15.0f)	rot = -15.0f;
		if(rot > 15.0f)		rot = 15.0f;
		if(keys[VK_SPACE]){ rot= 0.0; tip=0.0; } // Press Space_Bar in Orientation mode to centre.
	}
	else
	{
		if(keys[VK_LEFT])   {pad[0].sp[0] += ACC; lpR1 = FALSE;}	// Movement of player 1 (arrow keys).
		if(keys[VK_UP])		{pad[0].sp[1] += ACC; }
		if(keys[VK_RIGHT])  {pad[0].sp[2] += ACC; lpR1 = TRUE;}
		if(keys[VK_DOWN])   {pad[0].sp[3] += ACC; }
		
		if(keys['A'])		{pad[1].sp[0] += ACC; lpR2 = FALSE;} 	// Movement of player 1 (arrow keys).
		if(keys['W'])		{pad[1].sp[1] += ACC; }
		if(keys['D'])		{pad[1].sp[2] += ACC; lpR2 = TRUE;}
		if(keys['S'])		{pad[1].sp[3] += ACC; }
		
		if(!keys[VK_LEFT])  pad[0].sp[0] = 0.0f;	// Movement of player 1 (arrow keys).
		if(!keys[VK_UP])	pad[0].sp[1] = 0.0f;
		if(!keys[VK_RIGHT]) pad[0].sp[2] = 0.0f;
		if(!keys[VK_DOWN])  pad[0].sp[3] = 0.0f;
		
		if(!keys['A'])		pad[1].sp[0] = 0.0f;	// Movement of player 1 (arrow keys).
		if(!keys['W'])		pad[1].sp[1] = 0.0f;
		if(!keys['D'])		pad[1].sp[2] = 0.0f;
		if(!keys['S'])		pad[1].sp[3] = 0.0f;	
	}
}


void
Menu_CheckKeys()
{
	if (keys[VK_ESCAPE])	// Was ESC Pressed?
	{
		BASS_StreamPlay(click[woP-1],FALSE,BASS_SAMPLE_3D);
		woP = 4;			// Select Exit.
	}
			
	if (keys[VK_RETURN]) // Was Return Pressed?
	{
		if (woP == 1)
		{
			BASS_SetVolume(100);	// Reset volume to full. (Exit).
			BASS_Stop();
			rot = 0.0f;
			tip = -45.0f;
			WhichMenu = 2;
			SetUpGame();
		}

		if (woP == 2)
		{
			BASS_SetVolume(100);	// Reset volume to full. (Exit).
			BASS_Stop();
			rot = 0.0f;
			tip = 0.0f;
			WhichMenu = 3;
			SetUpGame();
		}

		if (woP == 4)
		{
			BASS_SetVolume(100);	// Reset volume to full. (Exit).
			BASS_Stop();
			done=TRUE;
		}
	}
				
	if (keys[VK_DOWN])			
	{
		if (!kd) 
		{
			BASS_StreamPlay(click[woP-1],FALSE,BASS_SAMPLE_3D);
			woP++;
			if(woP>4) woP = 1;
			kd = TRUE;	
		}
	}
	else kd = FALSE;


	if (keys[VK_UP])			
	{
		if (!ku) 
		{
			BASS_StreamPlay(click[woP-1],FALSE,BASS_SAMPLE_3D);
			woP--;
			if(woP<1) woP = 4;
			ku = TRUE;
		} 
	}
	else ku = FALSE;
}

void
PuckCollision()
{
	
	// First check whether to allow scoring, based on the puck's new position.
	if	((AtTop == TRUE && puk.Y - ((PUCK_HEIGHT*2)+0.01f) < 0.0f) || 
		 (AtTop == FALSE && puk.Y + ((PUCK_HEIGHT*2)+0.01f) > 0.0f)) 
	{ 
		ScoreAllowed = TRUE;
		if (puk.Y < 0.0f) AtTop = FALSE; else AtTop = TRUE;
	}
	
	
	
	bool imp = FALSE;
	// Walls of court: -
	if (puk.X - PUCK_LENGTH <= -1.0f)
	{
		puk.X = -1.0f + PUCK_LENGTH;
		puk.sp[0] = FALSE;
		puk.sp[2] = TRUE;
		BASS_StreamPlay(puck_impact[0],FALSE,BASS_SAMPLE_3D);
	}

	if (puk.X + PUCK_LENGTH >= 1.0f)
	{
		puk.X = 1.0f - PUCK_LENGTH;
		puk.sp[2] = FALSE;
		puk.sp[0] = TRUE;
		BASS_StreamPlay(puck_impact[1],FALSE,BASS_SAMPLE_3D);
	}

	if (puk.Y + PUCK_LENGTH >= 1.6f)
	{
		puk.Y = 1.6f - PUCK_LENGTH;
		puk.sp[1] = FALSE;
		puk.sp[3] = TRUE;
		BASS_StreamPlay(puck_impact[2],FALSE,BASS_SAMPLE_3D);
		if (ScoreAllowed)
		{
			score1++;
			ScoreAllowed = FALSE;	// One point scored, so no more allowed.
		}
	}
	
	if (puk.Y - PUCK_LENGTH <= -1.6f)
	{
		puk.Y = -1.6f + PUCK_LENGTH;
		puk.sp[3] = FALSE;
		puk.sp[1] = TRUE;
		BASS_StreamPlay(puck_impact[3],FALSE,BASS_SAMPLE_3D);
		if (ScoreAllowed)
		{
			score2++;
			ScoreAllowed = FALSE;	// One point scored, so no more allowed.
		}		
	}
	


	// Padels: -
	for (int ti = 0; ti < 2; ti++)
	{
		if (puk.X + PUCK_LENGTH >= pad[ti].X - PADEL_LENGTH && 
			puk.X - PUCK_LENGTH <= pad[ti].X + PADEL_LENGTH)
		{
			// Above Padel.
			if (puk.Y - PUCK_LENGTH >  pad[ti].Y &&
				puk.Y - PUCK_LENGTH <= pad[ti].Y + PADEL_HEIGHT)
			{
				puk.Y = pad[ti].Y + PUCK_LENGTH + PADEL_HEIGHT + pad[ti].sp[1];
				puk.sp[1] = TRUE;
				puk.sp[3] = FALSE;
				BASS_StreamPlay(puck_impact2[0],FALSE,BASS_SAMPLE_3D);

				//Player can direct puck: -
				if (ti == 0) {
					if (lpR1==FALSE) { puk.sp[0] = TRUE; puk.sp[2] = FALSE;} 
					else {puk.sp[2] = TRUE; puk.sp[0] = FALSE;}}
				if (ti == 1) {
					if (lpR2==FALSE) { puk.sp[0] = TRUE; puk.sp[2] = FALSE;} 
					else {puk.sp[2] = TRUE; puk.sp[0] = FALSE;}}
				puk.speed = (pad[ti].sp[1]*1.1);
				
			}
			// Below Padel.
			if (puk.Y + PUCK_LENGTH <  pad[ti].Y &&
				puk.Y + PUCK_LENGTH >= pad[ti].Y - PADEL_HEIGHT)
			{
				puk.Y = pad[ti].Y - PUCK_LENGTH - PADEL_HEIGHT - pad[ti].sp[1];
				puk.sp[3] = TRUE;
				puk.sp[1] = FALSE;
				BASS_StreamPlay(puck_impact2[1],FALSE,BASS_SAMPLE_3D);
				
				// Player can direct puck: -
				if (ti == 0) {
					if (lpR1==FALSE) { puk.sp[0] = TRUE; puk.sp[2] = FALSE;} 
					else {puk.sp[2] = TRUE; puk.sp[0] = FALSE;}}
				if (ti == 1) {
					if (lpR2==FALSE) { puk.sp[0] = TRUE; puk.sp[2] = FALSE;} 
					else {puk.sp[2] = TRUE; puk.sp[0] = FALSE;}}
				puk.speed = (pad[ti].sp[3]*1.1);
			}
		}
	}
	
	for (int tii = 0; tii < 2; tii++)
	{
		if (puk.Y - PUCK_HEIGHT <= pad[tii].Y + PADEL_HEIGHT && 
			puk.Y + PUCK_HEIGHT >= pad[tii].Y - PADEL_HEIGHT)
		{
			// Left of Padel.
			if (puk.X + PUCK_LENGTH <  pad[tii].X &&
				puk.X + PUCK_LENGTH >= pad[tii].X - PADEL_LENGTH)
			{
				//puk.X = pad[tii].X - PUCK_LENGTH - PADEL_LENGTH;
				puk.sp[0] = TRUE;
				puk.sp[2] = FALSE;
				BASS_StreamPlay(puck_impact2[1],FALSE,BASS_SAMPLE_3D);
			}
			// Right of Padel.
			if (puk.X - PUCK_LENGTH >  pad[tii].X &&
				puk.X - PUCK_LENGTH <= pad[tii].X + PADEL_LENGTH)
			{
				//puk.X = pad[tii].X + PUCK_LENGTH + PADEL_LENGTH;
				puk.sp[2] = TRUE;
				puk.sp[0] = FALSE;
				BASS_StreamPlay(puck_impact2[1],FALSE,BASS_SAMPLE_3D);
			}
		}
	}

}

void 
Collision(int t)
{
	// Collision of padels is taken care of in this function.
	
	// Left wall.
	if (pad[t].X - PADEL_LENGTH <= -1.0f) 
	{	
		pad[t].X = -1.0f + (PADEL_LENGTH);		// Padel repositioned.
		pad[t].sp[0] = 0.0f;					// Left speed nullified.
	}

	// Right wall.
	if (pad[t].X + PADEL_LENGTH >= 1.0f) 
	{
		pad[t].X = 1.0f - (PADEL_LENGTH);		// Padel repositioned.
		pad[t].sp[2] = 0.0f;					// Right speed nullified.
	}

	// Top wall.
	if (pad[t].Y + PADEL_HEIGHT >= 1.59f) 
	{
		pad[t].Y = 1.59f - (PADEL_HEIGHT);		// Padel repositioned.
		pad[t].sp[1] = 0.0f;					// Left speed nullified.
	}

	// Bottom wall.
	if (pad[t].Y - PADEL_HEIGHT <= -1.59f) 
	{
		pad[t].Y = -1.59f + (PADEL_HEIGHT);		// Padel repositioned.
		pad[t].sp[3] = 0.0f;					// Left speed nullified.
	}

	// Net Obstruction: -
	if (t == 0) // Bottom padel.
	{
		if (pad[t].Y + PADEL_HEIGHT >= -0.0001f) 
		{
			pad[t].Y = -0.0001f - (PADEL_HEIGHT);	// Padel repositioned.
			pad[t].sp[1] = 0.0f;					// Left speed nullified.
		}
	}
	
	if (t == 1) // Top padel.
	{
		if (pad[t].Y - PADEL_HEIGHT <= 0.0001f) 
		{
			pad[t].Y = -0.0001f + (PADEL_HEIGHT);		// Padel repositioned.
			pad[t].sp[3] = 0.0f;					// Left speed nullified.
		}
	}
}

void
MovePadels()
{
	for (int t = 0; t < 2; t++)
	{
			// Prevent speeding.
		for (int tto = 0; tto < 4; tto++) {
			if (pad[t].sp[tto] > TOP) pad[t].sp[tto] = TOP; }

		pad[t].X -= pad[t].sp[0];	// sp[0] = left.
		pad[t].Y += pad[t].sp[1];
		pad[t].X += pad[t].sp[2];
		pad[t].Y -= pad[t].sp[3];	// sp[3] = down.

		// Prevent negations of speed.
		/*for (int tt = 0; tt < 4; tt++) {
			pad[t].sp[tt] -= DAC;	// Decelerate.
			if (pad[t].sp[tt] < 0.0) pad[t].sp[tt] = 0.0f; }*/

		Collision(t);

	}
}

void
MovePuck()
{
	
	if (puk.speed < MIN_PUCK_SPEED) puk.speed = MIN_PUCK_SPEED;	// Make sure puck not too slow.
	if (puk.speed > MAX_PUCK_SPEED) puk.speed = MAX_PUCK_SPEED; // Make sure puck not too fast.
	
	if (puk.sp[0]) puk.X -= puk.speed;
	if (puk.sp[1]) puk.Y += puk.speed;
	if (puk.sp[2]) puk.X += puk.speed;
	if (puk.sp[3]) puk.Y -= puk.speed;

	PuckCollision();
}

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{
	MSG		msg;									// Windows Message Structure

	// Ask The User Which Screen Mode They Prefer
	/*if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
		fullscreen=FALSE;							// Windowed Mode
	}*/

	if (!CreateGLWindow("OpenGL Framework",960,720,32,fullscreen))	// Create OpenGL Window.
	{
		return 0;									// Quit If Window Was Not Created.
	}

	int a4 = Siosis_v1();	// Draw the logo.
	InitMenu();				// Set up the menu.

	while(!done)									// Loop That Runs While done=FALSE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;							// If So done=TRUE
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		else										// If There Are No Messages
		{
							
			if (active)								// Program Active?
			{	
				
				// THE PROGRAM LOOP.
				//##########################################################################
				// Check keys - in Main Menu.
				switch (WhichMenu)
				{
				case 1:
					Menu_CheckKeys();
					DrawMenu(woP);					
					break;
				case 2:
					Game_CheckKeys();
					Ai("Matazuri");
					MovePadels();
					MovePuck();
					DrawCourt();
					break;
				case 3:
					Game_CheckKeys();
					MovePadels();
					MovePuck();
					DrawCourt();
					break;
				}

				
				
				SwapBuffers(hDC);					// Swap Buffers (Double Buffering).		
				//##########################################################################
			}

			
		}
	}

	// Shutdown
	KillGLWindow();									// Kill The Window.
	return (msg.wParam);							// Exit The Program.
}

